#ifndef __VANILA_GARBAGE_COLLECTOR_HH__
#define __VANILA_GARBAGE_COLLECTOR_HH__

#include "vanila/value.h"
#include "utils/singleton.h"
#include <stack>
#include <vector>
#include <map>

namespace vanila
{
class GarbageCollector : public utils::Singleton<GarbageCollector>
{
public:
    GarbageCollector() noexcept;
    ~GarbageCollector() noexcept = default;

    //! \brief release the object instance which never been used
    void collectGarbage();

private:
    //! \brief mark the root object as reacheable
    void markRoots();

    //! \brief mark a value
    void markValue(Value* slot);
    void markValue(const Value& slot);

    //! \brief mark a object
    void markObject(Object* object);

    //! \brief values
    void markArray(std::vector<Value>& array);

    //! \brief mark table
    void markTable(std::map<ObjectString*, Value>& table);

private:
    //! \brief check all mark object, set them to black
    void traceReferences();

    //! \brief set a object to black
    void blackenObject(Object* object);

private:
    //! \brief release all white object
    void sweep();

    //! \brief remove the white string in string table
    void removeWhiteStrings();

private:
    std::stack<Object*> _grayStack;
};
}

#endif